﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Input;
using Amazon.SimpleDB;
using Amazon.SimpleDB.Model;
using AmzAttribute = Amazon.SimpleDB.Model.Attribute;

namespace SimpleDbBrowser.ViewModel
{
    /// <summary>
    /// The view model responsible for supplying the DeleteAttribute command.
    /// </summary>
    public sealed class DeleteAttributeViewModel : ViewModelBase
    {
        private readonly AmazonSimpleDB db;
        private AmzAttribute selectedAttribute;
        private string selectedDomain;
        private Item selectedItem;

        /// <summary>
        /// Initializes a new instance of the DeleteAttributeViewModel class.
        /// </summary>
        /// <param name="database">
        /// The database associated with the view model.
        /// </param>
        public DeleteAttributeViewModel(AmazonSimpleDB database)
        {
            if (database == null) throw new ArgumentNullException("database");

            this.db = database;

            this.DeleteAttribute = new RelayCommand(this.OnDeleteAttribute, this.CanDeleteAttribute);
        }

        /// <summary>
        /// Gets the command that deletes an attribute based on the state of 
        /// the view model.
        /// </summary>
        public ICommand DeleteAttribute { get; private set; }

        /// <summary>
        /// The attribute that will be deleted if the delete attribute command
        /// is executed.
        /// </summary>
        public AmzAttribute SelectedAttribute
        {
            get { return this.selectedAttribute; }

            set
            {
                if (this.selectedAttribute == value) return;

                this.selectedAttribute = value;
                this.OnSelectedAttributeChanged();
            }
        }

        /// <summary>
        /// The item that contains the attribute that will be deleted if the 
        /// delete attribute command is executed.
        /// </summary>
        public Item SelectedItem
        {
            get { return this.selectedItem; }

            set
            {
                if (this.selectedItem == value) return;

                this.selectedItem = value;
                this.OnSelectedItemChanged();
                Debug.WriteLine(string.Format("DeleteAttributeViewModel.SelectedItem changed to {0}",
                                              this.selectedItem == null ? "<null>" : this.selectedItem.Name));
            }
        }

        /// <summary>
        /// The domain that contains the item that contains the attribute that
        /// will be deleted if the delete attribute command is executed.
        /// </summary>
        public string SelectedDomain
        {
            get { return this.selectedDomain; }

            set
            {
                if (this.selectedDomain == value) return;

                this.selectedDomain = value;
                this.OnSelectedDomainChanged();
                Debug.WriteLine(String.Format("DeleteAttributeViewModel.SelectedDomain changed to {0}",
                                              this.selectedDomain));
            }
        }

        /// <summary>
        /// The view model's UI-friendly name.
        /// </summary>
        public override string DisplayName
        {
            get { return "Delete selected attribute"; }
            protected set { throw new NotSupportedException(); }
        }

        /// <summary>
        /// Handle the selected domain being changed.
        /// </summary>
        private void OnSelectedDomainChanged()
        {
            this.OnPropertyChanged("SelectedDomain");
        }

        /// <summary>
        /// Handle the selected attribute being changed.
        /// </summary>
        private void OnSelectedAttributeChanged()
        {
            this.OnPropertyChanged("SelectedAttribute");
        }

        /// <summary>
        /// Handle the selected item being changed.
        /// </summary>
        private void OnSelectedItemChanged()
        {
            this.OnPropertyChanged("SelectedItem");
        }

        /// <summary>
        /// Delete the selected attribute
        /// </summary>
        /// <param name="param">
        /// The execute parameter.
        /// </param>
        private void OnDeleteAttribute(object param)
        {
            var d = this.selectedDomain;
            var i = this.selectedItem;
            var a = this.selectedAttribute;

            var worker = new BackgroundWorker();
            worker.DoWork += (s, o) =>
                             {
                                 var req = new DeleteAttributesRequest().WithDomainName(d).WithItemName(i.Name);
                                 req.Attribute.Add(a);
                                 var resp = this.db.DeleteAttributes(req);
                             };

            worker.RunWorkerCompleted += (s, o) => this.OnAttributeDeleted(EventArgs.Empty);

            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Determines whether the DeleteAttribute command can be executed.
        /// </summary>
        /// <param name="param">
        /// The command parameter.  This is not used.
        /// </param>
        /// <returns>
        /// True if the command can be executed, otherwise false.
        /// </returns>
        private bool CanDeleteAttribute(object param)
        {
            return !string.IsNullOrWhiteSpace(this.selectedDomain) &&
                   (this.selectedItem != null) &&
                   (this.selectedAttribute != null);
        }

        /// <summary>
        /// Do tasks that must be performed once the delete attribute command 
        /// has successfully executed.
        /// </summary>
        /// <param name="args">
        /// This is not used.
        /// </param>
        private void OnAttributeDeleted(EventArgs args)
        {
            var tmp = this.AttributeDeleted;
            if (tmp != null)
            {
                tmp(this, args);
            }

            return;
        }

        /// <summary>
        /// Fires when an attribute has been deleted.
        /// </summary>
        public event EventHandler AttributeDeleted;
    }
}